#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<iconv.h>
#include<strings.h>
#include<errno.h>
#include "charsetconvert.h"
#include "utf8.h"

CCharSetConvert::CCharSetConvert()
{
	m_oBuf = NULL;
	m_pDetHandle= NULL;
	m_ConsOk = false;
	memset( m_charset,  0, CHARSET_MAX );

	Init();
}

CCharSetConvert::~CCharSetConvert()
{
	if( m_oBuf!=NULL )
	{
		delete (char*)m_oBuf;
		m_oBuf = NULL;
	}

	if( m_pDetHandle!=NULL )
	{
		chardet_destroy(m_pDetHandle);
		m_pDetHandle = NULL;
	}
}

void CCharSetConvert::Init()
{
	if( m_pDetHandle==NULL )
	{
		int iRet = chardet_create(&m_pDetHandle);
		if( iRet==0 )
		{
			m_ConsOk = true;
		}
	}
}

bool CCharSetConvert::IsConsOk()
{
	return this->m_ConsOk;
}

/*
 * Get the input buffer content charset, eg:gb18030, gb2312, utf-8
 *
 * return value:
 * 	 0: successful
 * 	-1: current construtor status is not ok
 * 	-2: handle input data error
 * */
char * CCharSetConvert::GetCharset(const char *inBuf, const unsigned int inLen, int & iOutRet) 
{
	if( !this->IsConsOk() )
	{
		iOutRet = -1;
		return NULL;
	}
    
    if( inBuf==NULL )
    {
        iOutRet = -2;
        return NULL;
    }

    if( utf8::is_valid( inBuf, inBuf+inLen ) )
    {
        memset( (void*)m_charset,  0, CHARSET_MAX );
        sprintf( m_charset, "UTF-8" );
    }
    else
    {
        int iRet = chardet_handle_data(this->m_pDetHandle, inBuf, inLen);
        if( iRet != 0 )
        {
            iOutRet = -2;
            return NULL;
        }

        chardet_data_end(this->m_pDetHandle);

        memset( (void*)m_charset,  0, CHARSET_MAX );
        chardet_get_charset(this->m_pDetHandle, (char*)this->m_charset, CHARSET_MAX);
        chardet_reset(this->m_pDetHandle);

        /*if( inLen>=6 )
        {
            const char *szSpecialWord1 = "\xe5\x90\xb8\xe6\xaf\x92";//吸毒
            const char *szSpecialWord2 = "\xe7\x99\xbd\xe7\xb2\x89";//白粉
            const char *szSpecialWord3 = "\xe7\x9c\x9f\xe4\xb8\xbb";
            if( NULL!=strstr(inBuf, szSpecialWord1) || NULL!=strstr(inBuf, szSpecialWord2) || NULL!=strstr(inBuf, szSpecialWord3))
            {
                memset( (void*)m_charset,  0, CHARSET_MAX );
                sprintf( m_charset, "UTF-8" );
            }
        }*/
    }

	iOutRet = 0;
	return this->m_charset;
}

/*
 * Convert source buffer to destination charset buffer
 * return value:
 * 	>0: Converted char counts
 * 	-1: argument error
 * 	-2: Get source buffer charset error
 * 	-3: Create iconv handle failed
 * */
int CCharSetConvert::CharsetConvert(const char *in_buf, const int inLen, char* out_buf, int out_max_len, const char *to_charset )
{
	if( out_buf==NULL || inLen==0 )
	{  
		return -1;  
	}  

	out_buf[0] = 0;  

	const char *from_charset;
	int oRet = 0;
	from_charset = this->GetCharset( in_buf, inLen, oRet );
	if( oRet<0 )
	{
		return -2;
	}

	if( strcasecmp(from_charset, to_charset) == 0 )
	{
		if( out_max_len<=inLen )  
		{
			strncat(out_buf, in_buf, out_max_len);  
		}
		else  
		{
			strncat( out_buf, in_buf, inLen );  
		}
		return out_max_len>inLen ? inLen : out_max_len;  
	}

	//convert  
	iconv_t cd;  
	int status = 0; //result  
	char *outbuf = out_buf;//iconv outptr begin  
	const char* inptr = in_buf;  
	char* outptr = outbuf;  
	size_t insize = inLen;  
	size_t outsize = out_max_len;  

	cd = iconv_open(to_charset, from_charset);  
	if((iconv_t)(-1) == cd)
	{  
		return -3;  
	}  

	iconv(cd, NULL, NULL, NULL, NULL);  
	while(insize > 0) 
	{
		size_t res = iconv(cd, (char**) &inptr, (size_t*)&insize, (char**)&outptr, (size_t*)&outsize);  
		if( outptr != outbuf )
		{  
			outbuf=outptr;  
			*outbuf=0;  
		}

		if( res == (size_t)(-1) )
		{  
			status = errno;
            break;
		}  
	}  

	iconv_close(cd);  
	return status<0 ? status : outptr-out_buf;
}

